package com.school.common.utils;

import java.util.Map;

import com.school.common.constant.CacheConstants;
import com.school.common.constant.Constants;
import com.school.common.core.domain.model.LoginUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * JWT令牌工具类，用于解释JWT令牌的概念、组成和在系统中的使用方式
 *
 * @author ruoyi
 */
public class JwtUtils {
    /**
     * 什么是JWT令牌
     *
     * JWT (JSON Web Token) 是一种基于JSON的开放标准(RFC 7519)，用于在各方之间安全地传输信息。
     * 此信息可以被验证和信任，因为它是数字签名的。JWT可以使用秘密(使用HMAC算法)或使用RSA的公钥/私钥对进行签名。
     *
     * 在本系统中，JWT主要用于身份验证和授权机制。当用户登录后，系统会生成一个JWT令牌，
     * 后续用户请求会携带此令牌，系统通过验证令牌来确认用户身份和权限。
     */

    /**
     * JWT令牌的组成部分
     *
     * JWT令牌由三部分组成，用点(.)分隔：
     * 1. Header(头部)：包含令牌类型和签名算法
     * 2. Payload(负载)：包含声明(claims)，如用户信息、过期时间等
     * 3. Signature(签名)：用于验证消息的完整性和真实性
     *
     * 在本系统中，Payload部分包含了登录用户的关键信息，如用户名、用户ID等。
     */

    /**
     * 系统中的JWT使用流程
     *
     * 1. 用户登录：用户提供用户名和密码进行登录
     * 2. 生成令牌：系统验证凭据后，调用TokenService.createToken()生成JWT令牌
     * 3. 存储令牌：
     *    - 服务器端：将令牌和用户信息存储在Redis中，过期时间为30分钟
     *    - 客户端：将令牌存储在Cookie中
     * 4. 请求验证：用户后续请求携带令牌，通过JwtAuthenticationTokenFilter进行验证
     * 5. 令牌刷新：当令牌即将过期时(相差不足20分钟)，系统会自动刷新令牌有效期
     * 6. 注销登录：用户注销时，系统从Redis中删除令牌信息
     */

    /**
     * 解析JWT令牌中的基本信息
     *
     * @param token  JWT令牌
     * @param secret 密钥
     * @return 令牌中的声明信息
     */
    public static Claims parseToken(String token, String secret) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 从JWT令牌中获取用户名
     *
     * @param token  JWT令牌
     * @param secret 密钥
     * @return 用户名
     */
    public static String getUsernameFromToken(String token, String secret) {
        Claims claims = parseToken(token, secret);
        return claims.getSubject();
    }

    /**
     * 从JWT令牌中获取登录用户标识
     *
     * @param token  JWT令牌
     * @param secret 密钥
     * @return 登录用户标识
     */
    public static String getLoginUserKeyFromToken(String token, String secret) {
        Claims claims = parseToken(token, secret);
        return (String) claims.get(Constants.LOGIN_USER_KEY);
    }

    /**
     * 生成Redis中的令牌键
     *
     * @param uuid 用户唯一标识
     * @return Redis中的令牌键
     */
    public static String getTokenKey(String uuid) {
        return CacheConstants.LOGIN_TOKEN_KEY + uuid;
    }

    /**
     * 解释JWT令牌在系统安全中的作用
     *
     * JWT令牌在本系统安全架构中扮演着重要角色：
     * 1. 无状态认证：服务器不需要在会话中存储用户信息，减轻服务器负担
     * 2. 单点登录：在多个系统间实现单点登录变得简单
     * 3. 信息交换：安全地在各方之间传输信息
     * 4. 防篡改：令牌签名确保信息在传输过程中不被篡改
     *
     * 系统结合了JWT和Redis存储，既利用了JWT的无状态特性，又通过Redis实现了灵活的令牌管理(如主动失效)
     */

    /**
     * JWT相关的安全建议
     *
     * 1. 密钥管理：确保JWT密钥安全存储，定期更换
     * 2. 令牌有效期：设置适当的令牌有效期，本系统默认为30分钟
     * 3. HTTPS传输：确保所有携带JWT令牌的通信通过HTTPS进行
     * 4. 令牌存储：客户端应安全存储令牌，避免XSS和CSRF攻击
     * 5. 权限验证：除了验证令牌有效性，还应验证用户是否具有访问资源的权限
     */
}
